From ca7aeee16d1c317346dda3be1d1934d23a6e6848 Mon Sep 17 00:00:00 2001 From: robertl Date: Fri, 6 Jul 2007 03:35:37 +0000 Subject: [PATCH] Gerhard Olsson starts adding lap support to Garmin protocol layer. --- garmin.c | 88 +++++++ jeeps/gps.h | 21 +- jeeps/gpsapp.c | 644 +++++++++++++++++++++++++----------------------- jeeps/gpsapp.h | 41 ++- jeeps/gpscom.c | 53 ++++ jeeps/gpscom.h | 6 + jeeps/gpsmem.c | 39 +++ jeeps/gpsmem.h | 2 + jeeps/gpsprot.c | 17 +- jeeps/gpsprot.h | 117 +++++++-- 10 files changed, 680 insertions(+), 348 deletions(-) diff --git a/garmin.c b/garmin.c index 9ee42c813..ad4ecd808 100644 --- a/garmin.c +++ b/garmin.c @@ -421,6 +421,94 @@ route_read(void) } +static +void +lap_read_as_track(void) +{ + int32 ntracks; + GPS_PLap *array; + route_head *trk_head = NULL; + int trk_num = 0; + int index; + int i; + + ntracks = GPS_Command_Get_Lap(portname, &array, waypt_read_cb); + if ( ntracks <= 0 ) + return; + for (i = 0; i < ntracks; i++) { + waypoint *wpt; + if (array[i]->index == -1){ + index=i; + } else { + index=array[i]->index; + index=i; + } + + if ((trk_head == NULL) || (i == 0) || + /* D906 - last track:index is the track index */ + (array[i]->index == -1 && array[i]->track_index != 255) || + /* D10xx - no real separator, use begin/end time to guess */ + (abs(array[i-1]->start_time + array[i]->total_time/100-array[i]->start_time) > 2) + ) { + static struct tm * stmp; + stmp = gmtime(&array[i]->start_time); + trk_head = route_head_alloc(); + /*For D906, we would like to use the track_index in the last packet instead...*/ + trk_head->rte_num = ++trk_num; + trk_head->rte_name = xmalloc(32); + strftime(trk_head->rte_name, 32, "%Y-%m-%dT%H:%M:%SZ", stmp); + track_add_head(trk_head); + + wpt = waypt_new(); + + wpt->longitude = array[i]->begin_lon; + wpt->latitude = array[i]->begin_lat; + wpt->heartrate = array[i]->avg_heart_rate; + wpt->cadence = array[i]->avg_cadence; + wpt->speed = array[i]->max_speed; + wpt->creation_time = array[i]->start_time; + wpt->microseconds = 0; + + wpt->shortname = xmalloc(8); + sprintf(wpt->shortname, "#%d-0", index); + wpt->description = xmalloc(128); + sprintf(wpt->description, "D:%f Cal:%d MS:%f AH:%d MH:%d AC:%d I:%d T:%d", + array[i]->total_distance, array[i]->calories, array[i]->max_speed, array[i]->avg_heart_rate, + array[i]->max_heart_rate, array[i]->avg_cadence, array[i]->intensity, array[i]->trigger_method); + + track_add_wpt(trk_head, wpt); + } +/*Allow even if no correct location, no skip if invalid */ +/* if (array[i]->no_latlon) { +* continue; +* } +*/ + wpt = waypt_new(); + + wpt->longitude = array[i]->end_lon; + wpt->latitude = array[i]->end_lat; + wpt->heartrate = array[i]->avg_heart_rate; + wpt->cadence = array[i]->avg_cadence; + wpt->speed = array[i]->max_speed; + wpt->creation_time = array[i]->start_time + array[i]->total_time/100; + wpt->microseconds = 10000*(array[i]->total_time % 100); + /*Add fields with no mapping in the description */ + wpt->shortname = xmalloc(8); + sprintf(wpt->shortname, "#%d", index); + wpt->description = xmalloc(128); + sprintf(wpt->description, "D:%f Cal:%d MS:%f AH:%d MH:%d AC:%d I:%d T:%d (%f,%f)", + array[i]->total_distance, array[i]->calories, array[i]->max_speed, array[i]->avg_heart_rate, + array[i]->max_heart_rate, array[i]->avg_cadence, array[i]->intensity, array[i]->trigger_method, + array[i]->begin_lon, array[i]->begin_lat); + + track_add_wpt(trk_head, wpt); + } + while(ntracks) { + GPS_Lap_Del(&array[--ntracks]); + } + xfree(array); +} + /* * Rather than propogate Garmin-specific data types outside of the Garmin * code, we convert the PVT (position/velocity/time) data from the receiver diff --git a/jeeps/gps.h b/jeeps/gps.h index e307b3aba..42018a6a2 100644 --- a/jeeps/gps.h +++ b/jeeps/gps.h @@ -96,6 +96,7 @@ typedef struct GPS_STrack unsigned int no_latlon:1; /* True if no valid lat/lon found. */ int32 dspl; /* Display on map? */ int32 colour; /* Colour */ + float distance; /* distance traveled in meters.*/ char trk_ident[256]; /* Track identifier */ } GPS_OTrack, *GPS_PTrack; @@ -166,9 +167,10 @@ typedef struct GPS_SWay } GPS_OWay, *GPS_PWay; /* - * Forerunner Lap data. + * Forerunner/Edge Lap data. */ -typedef struct GPS_SLap_Data { +typedef struct GPS_SLap { + uint32 index; /* unique index in device or -1 */ time_t start_time; uint32 total_time; /* Hundredths of a second */ float total_distance; /* In meters */ @@ -177,8 +179,19 @@ typedef struct GPS_SLap_Data { double end_lat; double end_lon; int16 calories; - UC track_index; -} GPS_OLap_Data, *GPS_PLap_Data; + uint32 track_index; /* ref to track or -1 */ + float max_speed; /* In meters per second */ + unsigned char avg_heart_rate; /* In beats-per-minute, 0 if invalid */ + unsigned char max_heart_rate; /* In beats-per-minute, 0 if invalid */ + unsigned char intensity; /* Same as D1001 */ + unsigned char avg_cadence; /* In revolutions-per-minute, 0xFF if invalid */ + unsigned char trigger_method; + /*Some D1015 unknown */ + /* unsigned char unk1015_1; + int16 unk1015_2; + int16 unk1015_3; + */ +} GPS_OLap, *GPS_PLap; typedef int (*pcb_fn) (int, struct GPS_SWay **); diff --git a/jeeps/gpsapp.c b/jeeps/gpsapp.c index 3190681fd..b0474ab2a 100644 --- a/jeeps/gpsapp.c +++ b/jeeps/gpsapp.c @@ -98,10 +98,6 @@ static void GPS_D400_Send(UC *data, GPS_PWay way, int32 *len); static void GPS_D403_Send(UC *data, GPS_PWay way, int32 *len); static void GPS_D450_Send(UC *data, GPS_PWay way, int32 *len); -static int32 GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd); -static int32 GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd); -static int32 GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd); -static int32 GPS_D551_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd); static void GPS_D500_Send(UC *data, GPS_PAlmanac alm); static void GPS_D501_Send(UC *data, GPS_PAlmanac alm); static void GPS_D550_Send(UC *data, GPS_PAlmanac alm); @@ -235,13 +231,18 @@ static int32 GPS_A000(const char *port) #endif gps_pvt_transfer = -1; gps_pvt_type = -1; - gps_prx_waypt_transfer = -1; - gps_prx_waypt_type = -1; gps_trk_transfer = -1; gps_trk_type = -1; gps_trk_hdr_type = -1; gps_rte_link_type = -1; + gps_prx_waypt_transfer = -1; + gps_prx_waypt_type = -1; + gps_almanac_transfer = -1; + gps_almanac_type = -1; + gps_lap_transfer = -1; + gps_lap_type = -1; + if(!GPS_Device_Wait(fd)) { GPS_Warning("A001 protocol not supported"); @@ -353,6 +354,8 @@ static void GPS_A001(GPS_PPacket packet) gps_prx_waypt_type = -1; gps_almanac_transfer = -1; gps_almanac_type = -1; + gps_lap_transfer = -1; + gps_lap_type = -1; entries = packet->n / 3; p = packet->data; @@ -411,15 +414,36 @@ static void GPS_A001(GPS_PPacket packet) case 600: gps_date_time_transfer = pA600; break; + case 650: + /* FlightBook Transfer Protocol */ + break; case 700: gps_position_transfer = pA700; break; case 800: gps_pvt_transfer = pA800; break; + case 906: + gps_lap_transfer = pA906; + break; case 1000: gps_run_transfer = pA1000; break; + case 1002: + gps_workout_transfer = pA1002; + break; + case 1004: + gps_user_profile_transfer = pA1004; + break; + case 1005: + gps_workout_limits_transfer = pA1005; + break; + case 1006: + gps_course_transfer = pA1006; + break; + case 1009: + gps_course_limits_transfer = pA1009; + break; } break; @@ -532,27 +556,14 @@ static void GPS_A001(GPS_PPacket packet) continue; } - else if(lasta<500) { - if(data<=110 && data>=100) - { - gps_prx_waypt_type = data; - continue; - } - if(data<153 && data>=150) - { - gps_prx_waypt_type = data; - continue; - } - if(data<156 && data>=154) - { - gps_prx_waypt_type = data; - continue; - } - if(data<451) - { - if(data==400) + if((data<=110 && data>=100) || + (data<153 && data>=150) || + (data<156 && data>=154)) { + gps_prx_waypt_type = data; + } + else if(data==400) gps_prx_waypt_type = pD400; else if(data==403) gps_prx_waypt_type = pD403; @@ -562,7 +573,6 @@ static void GPS_A001(GPS_PPacket packet) GPS_Protocol_Error(tag,data); continue; } - } else if(lasta<600) { @@ -579,7 +589,7 @@ static void GPS_A001(GPS_PPacket packet) continue; } - else if(lasta<700) + else if(lasta<650) { if (data == 600) { gps_date_time_type = pD600; @@ -590,6 +600,13 @@ static void GPS_A001(GPS_PPacket packet) } continue; } + + else if(lasta<651) + { + /* FlightBook Transfer Protocol, not handled */ + continue; + } + else if(lasta<800) { if(data!=700) @@ -598,6 +615,7 @@ static void GPS_A001(GPS_PPacket packet) gps_position_type = pD700; continue; } + else if(lasta<900) { if (data == 800) @@ -609,10 +627,87 @@ static void GPS_A001(GPS_PPacket packet) */ continue; } + else if (lasta < 1000) { if (data == 906) gps_lap_type = pD906; + else if (data == 1001) + gps_lap_type = pD1001; + else if (data == 1011) + gps_lap_type = pD1011; + else if (data == 1015) + gps_lap_type = pD1015; + continue; + } + + else if (lasta < 1002) + { + if (data == 1000) + gps_run_type = pD1000; + else if (data == 1009) + gps_run_type = pD1009; + else if (data == 1010) + gps_run_type = pD1010; + continue; + } + + else if (lasta < 1003) + { + if (data == 1002) + gps_workout_type = pD1002; + else if (data == 1008) + gps_workout_type = pD1008; + continue; + } + + else if (lasta < 1004) + { + if (data == 1003) + gps_workout_occurrence_type = pD1003; + continue; + } + + else if (lasta < 1005) + { + if (data == 1004) + gps_user_profile_type = pD1004; + continue; + } + + else if (lasta < 1006) + { + if (data == 1005) + gps_workout_limits_type = pD1005; + continue; + } + + else if (lasta < 1007) + { + if (data == 1006) + gps_course_type = pD1006; + continue; + } + + else if (lasta < 1008) + { + if (data == 1007) + gps_course_lap_type = pD1007; + continue; + } + + else if (lasta < 1009) + { + if (data == 1012) + gps_course_point_type = pD1012; + continue; + } + + else if (lasta < 1010) + { + if (data == 1013) + gps_course_limits_type = pD1013; + continue; } } } @@ -4006,7 +4101,7 @@ void GPS_D302b_Get(GPS_PTrack *trk, UC *data) /* @func GPS_D303b_Get ****************************************************** ** -** Get track data (A302 protocol) -- XXX used in Forerunner 301 +** Get track data (A302 protocol) -- used in Forerunner 301 ** ** @param [w] trk [GPS_PTrack *] track ** @param [r] data [UC *] packet data @@ -4073,7 +4168,8 @@ void GPS_D303b_Get(GPS_PTrack *trk, UC *data) */ switch (gps_trk_type) { case pD304: - p+=4; /* A float indicating number of meters travelled. */ + (*trk)->distance = GPS_Util_Get_Float(p); + p+=sizeof(float); /* A float indicating number of meters travelled. */ (*trk)->heartrate = (*p++); /* crank cadence, RPM, 0xff if invalid. */ @@ -4866,34 +4962,33 @@ int32 GPS_A500_Get(const char *port, GPS_PAlmanac **alm) { static UC data[2]; gpsdevh *fd; - GPS_PPacket tra; - GPS_PPacket rec; - int32 n; - int32 i; - int32 ret; + GPS_PPacket trapkt; + GPS_PPacket recpkt; + int32 i, n; + + if (gps_almanac_transfer == -1) + return GPS_UNSUPPORTED; if(!GPS_Device_On(port, &fd)) return gps_errno; - if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + if (!(trapkt = GPS_Packet_New() ) || !(recpkt = GPS_Packet_New())) return MEMORY_ERROR; - GPS_Util_Put_Short(data, COMMAND_ID[gps_device_command].Cmnd_Transfer_Alm); - GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Command_Data, + GPS_Make_Packet(&trapkt, LINK_ID[gps_link_type].Pid_Command_Data, data,2); - if(!GPS_Write_Packet(fd,tra)) + if(!GPS_Write_Packet(fd,trapkt)) return gps_errno; - if(!GPS_Get_Ack(fd, &tra, &rec)) + if(!GPS_Get_Ack(fd, &trapkt, &recpkt)) return gps_errno; - - if(!GPS_Packet_Read(fd, &rec)) + if(!GPS_Packet_Read(fd, &recpkt)) return gps_errno; - if(!GPS_Send_Ack(fd, &tra, &rec)) + if(!GPS_Send_Ack(fd, &trapkt, &recpkt)) return gps_errno; - n = GPS_Util_Get_Short(rec->data); + n = GPS_Util_Get_Short(recpkt->data); if(n) if(!((*alm)=(GPS_PAlmanac *)malloc(n*sizeof(GPS_PAlmanac)))) @@ -4901,51 +4996,67 @@ int32 GPS_A500_Get(const char *port, GPS_PAlmanac **alm) GPS_Error("A500_Get: Insufficient memory"); return MEMORY_ERROR; } - for(i=0;idata, &((*alm)[i])); break; case pD501: - ret = GPS_D501_Get(*alm,n,fd); + GPS_A500_Translate(recpkt->data, &((*alm)[i])); + (*alm)[i]->hlth=recpkt->data[42]; break; case pD550: - ret = GPS_D550_Get(*alm,n,fd); + (*alm)[i]->svid = recpkt->data[0]; + GPS_A500_Translate(recpkt->data+1, &((*alm)[i])); break; case pD551: - ret = GPS_D551_Get(*alm,n,fd); + (*alm)[i]->svid = recpkt->data[0]; + GPS_A500_Translate(recpkt->data+1, &((*alm)[i])); + (*alm)[i]->hlth = recpkt->data[43]; break; default: GPS_Error("A500_GET: Unknown almanac protocol"); return PROTOCOL_ERROR; } + /* Cheat and don't _really_ pass the trkpt back */ +/* cb(n, NULL);*/ + } - if(ret < 0) return ret; - if(ret != n) - { - GPS_Error("A500_GET: Almanac entry number mismatch"); + if(!GPS_Packet_Read(fd, &recpkt)) + return gps_errno; + if(!GPS_Send_Ack(fd, &trapkt, &recpkt)) + return gps_errno; + if(recpkt->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) { + GPS_Error("A500_Get: Error transferring almanac"); return FRAMING_ERROR; } + if(i != n) { + GPS_Error("A500_GET: Almanac entry number mismatch"); + return FRAMING_ERROR; + } - GPS_Packet_Del(&tra); - GPS_Packet_Del(&rec); + GPS_Packet_Del(&trapkt); + GPS_Packet_Del(&recpkt); if(!GPS_Device_Off(fd)) return gps_errno; - return ret; + return n; } - - - /* @func GPS_A500_Send ************************************************** ** ** Send almanac to GPS @@ -5125,216 +5236,6 @@ int32 GPS_A500_Send(const char *port, GPS_PAlmanac *alm, int32 n) return 1; } - - -/* @funcstatic GPS_D500_Get ******************************************** -** -** Get almanac data -** -** @param [w] alm [GPS_PAlmanac *] almanac array -** @param [r] entries [int32] number of packets to receive -** @param [r] fd [int32] file descriptor -** -** @return [int32] number of entries read -************************************************************************/ -static int32 GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd) -{ - GPS_PPacket tra; - GPS_PPacket rec; - int32 i; - - if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) - return MEMORY_ERROR; - - - for(i=0;idata, &alm[i]); - } - - - if(!GPS_Packet_Read(fd, &rec)) - return gps_errno; - - if(!GPS_Send_Ack(fd, &tra, &rec)) - return gps_errno; - - - if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) - { - GPS_Error("D500_GET: Error transferring almanac"); - return FRAMING_ERROR; - } - - GPS_Packet_Del(&tra); - GPS_Packet_Del(&rec); - - return i; -} - - -/* @funcstatic GPS_D501_Get ******************************************** -** -** Get almanac data -** -** @param [w] alm [GPS_PAlmanac *] almanac array -** @param [r] entries [int32] number of packets to receive -** @param [r] fd [int32] file descriptor -** -** @return [int32] number of entries read -************************************************************************/ -static int32 GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd) -{ - GPS_PPacket tra; - GPS_PPacket rec; - int32 i; - - if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) - return MEMORY_ERROR; - - - for(i=0;idata, &alm[i]); - alm[i]->hlth=rec->data[42]; - } - - - if(!GPS_Packet_Read(fd, &rec)) - return gps_errno; - if(!GPS_Send_Ack(fd, &tra, &rec)) - return gps_errno; - - - if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) - { - GPS_Error("D501_GET: Error transferring almanac"); - return FRAMING_ERROR; - } - - GPS_Packet_Del(&tra); - GPS_Packet_Del(&rec); - - return i; -} - - - -/* @funcstatic GPS_D550_Get ********************************************* -** -** Get almanac data -** -** @param [w] alm [GPS_PAlmanac *] almanac array -** @param [r] entries [int32] number of packets to receive -** @param [r] fd [int32] file descriptor -** -** @return [int32] number of entries read -************************************************************************/ -static int32 GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd) -{ - GPS_PPacket tra; - GPS_PPacket rec; - int32 i; - - if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) - return MEMORY_ERROR; - - - for(i=0;isvid = rec->data[0]; - GPS_A500_Translate(rec->data+1, &alm[i]); - } - - - if(!GPS_Packet_Read(fd, &rec)) - return gps_errno; - if(!GPS_Send_Ack(fd, &tra, &rec)) - return gps_errno; - - if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) - { - GPS_Error("D550_GET: Error transferring almanac"); - return FRAMING_ERROR; - } - - GPS_Packet_Del(&tra); - GPS_Packet_Del(&rec); - - return i; -} - - - -/* @funcstatic GPS_D551_Get ********************************************* -** -** Get almanac data -** -** @param [w] alm [GPS_PAlmanac *] almanac array -** @param [r] entries [int32] number of packets to receive -** @param [r] fd [int32] file descriptor -** -** @return [int32] number of entries read -************************************************************************/ -static int32 GPS_D551_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd) -{ - GPS_PPacket tra; - GPS_PPacket rec; - int32 i; - - if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) - return MEMORY_ERROR; - - - for(i=0;isvid = rec->data[0]; - GPS_A500_Translate(rec->data+1, &alm[i]); - alm[i]->hlth = rec->data[43]; - } - - - if(!GPS_Packet_Read(fd, &rec)) - return gps_errno; - if(!GPS_Send_Ack(fd, &tra, &rec)) - return gps_errno; - - - if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) - { - GPS_Error("D551_GET: Error transferring almanac\n"); - return FRAMING_ERROR; - } - - GPS_Packet_Del(&tra); - GPS_Packet_Del(&rec); - - return i; -} - - - /* @funcstatic GPS_A500_Translate *************************************** ** ** Translate almanac packet to almanac structure @@ -6104,23 +6005,22 @@ void GPS_D800_Get(GPS_PPacket packet, GPS_PPvt_Data *pvt) return; } -#if XXX /* FIXME/PLACEHOLDER */ /* @func GPS_A906_Get ****************************************************** ** ** Get lap data from GPS ** ** @param [r] port [const char *] serial port -** @param [w] trk [GPS_PLap_Data **] lap array +** @param [w] trk [GPS_PLap **] lap array ** ** @return [int32] number of lap entries ************************************************************************/ -int32 GPS_A906_Get(const char *port, GPS_OLap_Data **lap) +int32 GPS_A906_Get(const char *port, GPS_PLap **lap, pcb_fn cb) { static UC data[2]; gpsdevh *fd; - GPS_PPacket lappkt; + GPS_PPacket trapkt; GPS_PPacket recpkt; int32 i, n; @@ -6130,20 +6030,20 @@ int32 GPS_A906_Get(const char *port, GPS_OLap_Data **lap) if (!GPS_Device_On(port, &fd)) return gps_errno; - if (!(lappkt = GPS_Packet_New() ) || !(recpkt = GPS_Packet_New())) + if (!(trapkt = GPS_Packet_New() ) || !(recpkt = GPS_Packet_New())) return MEMORY_ERROR; GPS_Util_Put_Short(data, COMMAND_ID[gps_device_command].Cmnd_Transfer_Lap); - GPS_Make_Packet(&lappkt, LINK_ID[gps_link_type].Pid_Command_Data, + GPS_Make_Packet(&trapkt, LINK_ID[gps_link_type].Pid_Command_Data, data,2); - if(!GPS_Write_Packet(fd,lappkt)) + if(!GPS_Write_Packet(fd,trapkt)) return gps_errno; - if(!GPS_Get_Ack(fd, &lappkt, &recpkt)) + if(!GPS_Get_Ack(fd, &trapkt, &recpkt)) return gps_errno; if(!GPS_Packet_Read(fd, &recpkt)) return gps_errno; - if(!GPS_Send_Ack(fd, &lappkt, &recpkt)) + if(!GPS_Send_Ack(fd, &trapkt, &recpkt)) return gps_errno; n = GPS_Util_Get_Short(recpkt->data); @@ -6155,48 +6055,86 @@ int32 GPS_A906_Get(const char *port, GPS_OLap_Data **lap) return MEMORY_ERROR; } - for(i=0;idata); + break; + default: + GPS_Error("A906_Get: Unknown Lap protocol %d\n", gps_lap_type); + return PROTOCOL_ERROR; + } + + /* Cheat and don't _really_ pass the trkpt back */ + cb(n, NULL); } - if (ret != n) { - GPS_Error("A906_Get: got %d lap entries. Expected %d\n", ret, n); + + if(!GPS_Packet_Read(fd, &recpkt)) + return gps_errno; + if(!GPS_Send_Ack(fd, &trapkt, &recpkt)) + return gps_errno; + if(recpkt->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) { + GPS_Error("A906_Get: Error transferring laps"); return FRAMING_ERROR; } - GPS_Packet_Del(&lap); - GPS_Packet_Del(&rec); + + if(i != n) { + GPS_Error("A906_GET: Lap entry number mismatch"); + return FRAMING_ERROR; + } + + GPS_Packet_Del(&trapkt); + GPS_Packet_Del(&recpkt); if (!GPS_Device_Off(fd)) return gps_errno; - - return ret; + return n; } -#endif /* FIXME */ -/* @func GPS_D906_Get ****************************************************** +/* @func GPS_D1011b_Get ****************************************************** ** -** Convert packet to lap structure +** Convert packet D906, D1001, D1011, D1015 to lap structure ** ** @param [r] packet [GPS_PPacket] packet -** @param [w] pvt [GPS_PLap_Data *] lap structure +** @param [w] pvt [GPS_PLap *] lap structure ** ** @return [void] ************************************************************************/ -void GPS_D906_Get(GPS_PPacket packet, GPS_PLap_Data *Lap) +void GPS_D1011b_Get(GPS_PLap *Lap, UC *p) { - UC *p; uint32 t; - p = packet->data; + /* Lap index (not in D906) */ + switch(gps_lap_type) { + case pD906: + (*Lap)->index = -1; + break; + case pD1001: + (*Lap)->index = GPS_Util_Get_Uint(p); + p+=sizeof(uint32); + break; + case pD1011: + case pD1015: + (*Lap)->index = GPS_Util_Get_Short(p); + p+=sizeof(uint16); + p+=sizeof(uint16); /*unused*/ + break; + default: + break; + } t = GPS_Util_Get_Uint(p); (*Lap)->start_time = GPS_Math_Gtime_To_Utime((time_t)t); @@ -6207,7 +6145,10 @@ void GPS_D906_Get(GPS_PPacket packet, GPS_PLap_Data *Lap) (*Lap)->total_distance = GPS_Util_Get_Float(p); p+=sizeof(float); - + if(gps_lap_type != pD906){ + (*Lap)->max_speed = GPS_Util_Get_Float(p); + p+=sizeof(float); + } (*Lap)->begin_lat = GPS_Math_Semi_To_Deg(GPS_Util_Get_Int(p)); p+=sizeof(int32); @@ -6221,16 +6162,53 @@ void GPS_D906_Get(GPS_PPacket packet, GPS_PLap_Data *Lap) (*Lap)->calories = GPS_Util_Get_Short(p); p+=sizeof(int16); - (*Lap)->track_index = *p++; + /* Track index, only in D906*/ + if(gps_lap_type == pD906){ + (*Lap)->track_index = *p++; + p++; /*Unused*/ + + /*Last field, no more to do */ + return; + } else { + (*Lap)->track_index = -1; + } + + (*Lap)->avg_heart_rate = *p++; + (*Lap)->max_heart_rate = *p++; + (*Lap)->intensity = *p++; + + switch(gps_lap_type) { + case pD1001: + /*No more fields */ + return; + case pD1011: + case pD1015: + (*Lap)->avg_cadence = *p++; + (*Lap)->trigger_method = *p++; + break; + default: + /*pD906 already returned*/ + break; + } + + if (gps_lap_type==pD1015) { + /*some unknown fields like 04 dc 44 ff ff */ + /* (*Lap)->unk1015_1 = *p++; normally 4? + (*Lap)->unk1015_2 = GPS_Util_Get_Short(p);wkt related , ffff otherwise + p+=sizeof(int16); + (*Lap)->unk1015_3 = GPS_Util_Get_Short(p);ffff ? + p+=sizeof(int16); + */ + } return; } + /* * It's unfortunate that these aren't constant and therefore switchable, * but they really are runtime variable. Sigh. */ - const char * Get_Pkt_Type(unsigned char p, unsigned short d0, const char **xinfo) { @@ -6259,10 +6237,25 @@ Get_Pkt_Type(unsigned char p, unsigned short d0, const char **xinfo) case 452: *xinfo = "Xfer Wkt Occurrences"; break; case 453: *xinfo = "Xfer User Profile "; break; case 454: *xinfo = "Xfer Wkt Limits"; break; + case 561: *xinfo = "Xfer Courses"; break; + case 562: *xinfo = "Xfer Course Laps"; break; + case 563: *xinfo = "Xfer Course Point"; break; + case 564: *xinfo = "Xfer Course Tracks"; break; + case 565: *xinfo = "Xfer Course Limits"; break; + default: *xinfo = "Unknown"; } return "CMDDAT"; } + if (p == LT.Pid_Protocol_Array) + return "PRTARR"; + if (p == LT.Pid_Product_Rqst) + return "PRDREQ"; + if (p == LT.Pid_Product_Data) + return "PRDDAT"; + if (p == LT.Pid_Ext_Product_Data) + return "PRDEDA"; + if (p == LT.Pid_Xfer_Cmplt) return "XFRCMP"; if (p == LT.Pid_Date_Time_Data) @@ -6291,19 +6284,44 @@ Get_Pkt_Type(unsigned char p, unsigned short d0, const char **xinfo) return "LNKDAT"; if (p == LT.Pid_Trk_Hdr) return "TRKHDR"; - if (p == LT.Pid_Protocol_Array) - return "PRTARR"; - if (p == LT.Pid_Product_Rqst) - return "PRDREQ"; - if (p == LT.Pid_Product_Data) - return "PRDDAT"; + + if (p == LT.Pid_FlightBook_Record) + return "FLIBOO"; + if (p == LT.Pid_Lap) + return "LAPDAT"; + if (p == LT.Pid_Wpt_Cat_Data) + return "WPTCAT"; + if (p == LT.Pid_Run) + return "RUNDAT"; + if (p == LT.Pid_Workout) + return "WKTDAT"; + if (p == LT.Pid_Workout_Occurrence) + return "WKTOCC"; + if (p == LT.Pid_Fitness_User_Profile) + return "UPROFI"; + if (p == LT.Pid_Workout_Limits) + return "WKTLIM"; + if (p == LT.Pid_Course) + return "CRSDAT"; + if (p == LT.Pid_Course_Lap) + return "CRSLAP"; + if (p == LT.Pid_Course_Point) + return "CRSPOI"; + if (p == LT.Pid_Course_Trk_Hdr) + return "CRSTHD"; + if (p == LT.Pid_Course_Trk_Data) + return "CRSTDA"; + if (p == LT.Pid_Course_Limits) + return "CRSLIM"; + if (p == LT.Pid_Trk2_Hdr) + return "TRKHD2"; + if (p == GUSB_REQUEST_BULK) return "REQBLK"; if (p == GUSB_SESSION_START) return "SESREQ"; if (p == GUSB_SESSION_ACK) return "SESACK"; - if (p == 152) - return "WPTCAT"; + return "UNKNOWN"; } diff --git a/jeeps/gpsapp.h b/jeeps/gpsapp.h index ee6416847..677b448d9 100644 --- a/jeeps/gpsapp.h +++ b/jeeps/gpsapp.h @@ -23,13 +23,13 @@ int32 GPS_A201_Send(const char *port, GPS_PWay *way, int32 n); int32 GPS_A300_Get(const char *port, GPS_PTrack **trk, pcb_fn cb); int32 GPS_A301_Get(const char *port, GPS_PTrack **trk, pcb_fn cb); int32 GPS_A300_Send(const char *port, GPS_PTrack *trk, int32 n); -int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n); +int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n); /*A302*/ int32 GPS_D300_Get(GPS_PTrack *trk, int32 entries, gpsdevh *h); void GPS_D300b_Get(GPS_PTrack *trk, UC *data); void GPS_D301b_Get(GPS_PTrack *trk, UC *data); void GPS_D302b_Get(GPS_PTrack *trk, UC *data); -void GPS_D303b_Get(GPS_PTrack *trk, UC *data); +void GPS_D303b_Get(GPS_PTrack *trk, UC *data); /*D304*/ void GPS_D310_Get(GPS_PTrack *trk, UC *s); void GPS_D311_Get(GPS_PTrack *trk, UC *s); void GPS_D300_Send(UC *data, GPS_PTrack trk); @@ -58,6 +58,43 @@ int32 GPS_A800_Off(const char *port, gpsdevh **fd); int32 GPS_A800_Get(gpsdevh **fd, GPS_PPvt_Data *packet); void GPS_D800_Get(GPS_PPacket packet, GPS_PPvt_Data *pvt); +int32 GPS_A906_Get(const char *port, GPS_PLap **lap, pcb_fn cb); +void GPS_D1011b_Get(GPS_PLap *Lap,UC *data); /*D906 D1001 D1015*/ + +/* Unhandled documented protocols, as of: + Garmin Device Interface Specification, May 19, 2006, Drawing Number: 001-00063-00 Rev. C +A650 – FlightBook Transfer Protocol +A1000 – Run Transfer Protocol + Capability A1000: D1009 + D1000 D1010 +A1002 – Workout Transfer Protocol + Capability A1002: D1008 + D1002 + Capability A1003: D1003 +A1004 – Fitness User Profile Transfer Protocol + Capability A1004: D1004 +A1005 – Workout Limits Transfer Protocol + Capability A1005: D1005 +A1006 – Course Transfer Protocol + Capability A1006: D1006 + Capability A1007: D1007 + Capability A1008: D1012 +A1009 – Course Limits Transfer Protocol + Capability A1009: D1013 +*/ +/* Unimplemted and Undocumented, as listed from the following device/sw: + GF305 3.70 + +Capability A601: D601 +Capability A801: D801 + +Capability A902: +Capability A903: +Capability A907: D907 D908 D909 D910 +Capability A918: D918 +Capability A1013: D1014 +*/ + const char * Get_Pkt_Type(unsigned char p, unsigned short d0, const char **xinfo); diff --git a/jeeps/gpscom.c b/jeeps/gpscom.c index e2fe2afd6..3063b510a 100644 --- a/jeeps/gpscom.c +++ b/jeeps/gpscom.c @@ -361,6 +361,9 @@ int32 GPS_Command_Get_Almanac(const char *port, GPS_PAlmanac **alm) { int32 ret=0; + if(gps_almanac_transfer == -1) + return GPS_UNSUPPORTED; + switch(gps_almanac_transfer) { case pA500: @@ -391,6 +394,9 @@ int32 GPS_Command_Send_Almanac(const char *port, GPS_PAlmanac *alm, int32 n) { int32 ret=0; + if(gps_almanac_transfer == -1) + return GPS_UNSUPPORTED; + switch(gps_almanac_transfer) { case pA500: @@ -635,3 +641,50 @@ int32 GPS_Command_Pvt_Get(gpsdevh **fd, GPS_PPvt_Data *pvt) return ret; } + +/* @func GPS_Command_Get_Lap *************************************** +** +** Get lap from GPS +** +** @param [r] port [const char *] serial port +** @param [w] way [GPS_PLap **] pointer to lap array +** +** @return [int32] number of lap entries +************************************************************************/ + +int32 GPS_Command_Get_Lap(const char *port, GPS_PLap **lap, pcb_fn cb) +{ + int32 ret=0; + + if(gps_lap_transfer == -1) + return GPS_UNSUPPORTED; + + switch(gps_lap_transfer) + { + case pA906: + ret = GPS_A906_Get(port,lap, cb); + break; + default: + GPS_Error("Get_Lap: Unknown lap protocol"); + return PROTOCOL_ERROR; + } + + return ret; +} + /*Stubs for unimplemented stuff*/ +int32 GPS_Command_Get_Workout(const char *port, void **lap, int (*cb)(int, struct GPS_SWay **)){ + return 0; +} +int32 GPS_Command_Get_Fitness_User_Profile(const char *port, void **lap, int (*cb)(int, struct GPS_SWay **)){ + return 0; +} +int32 GPS_Command_Get_Workout_Limits(const char *port, void **lap, int (*cb)(int, struct GPS_SWay **)){ + return 0; +} +int32 GPS_Command_Get_Course(const char *port, void **lap, int (*cb)(int, struct GPS_SWay **)){ + return 0; +} +int32 GPS_Command_Get_Course_Limits(const char *port, void **lap, int (*cb)(int, struct GPS_SWay **)){ + return 0; +} + diff --git a/jeeps/gpscom.h b/jeeps/gpscom.h index 96e10f055..4c490cd42 100644 --- a/jeeps/gpscom.h +++ b/jeeps/gpscom.h @@ -37,7 +37,13 @@ int32 GPS_Command_Send_Proximity(const char *port, GPS_PWay *way, int32 n); int32 GPS_Command_Get_Route(const char *port, GPS_PWay **way); int32 GPS_Command_Send_Route(const char *port, GPS_PWay *way, int32 n); +int32 GPS_Command_Get_Lap(const char *port, GPS_PLap **lap, int (*cb)(int, struct GPS_SWay **)); +int32 GPS_Command_Get_Workout(const char *port, void **lap, int (*cb)(int, struct GPS_SWay **)); +int32 GPS_Command_Get_Fitness_User_Profile(const char *port, void **lap, int (*cb)(int, struct GPS_SWay **)); +int32 GPS_Command_Get_Workout_Limits(const char *port, void **lap, int (*cb)(int, struct GPS_SWay **)); +int32 GPS_Command_Get_Course(const char *port, void **lap, int (*cb)(int, struct GPS_SWay **)); +int32 GPS_Command_Get_Course_Limits(const char *port, void **lap, int (*cb)(int, struct GPS_SWay **)); #endif #ifdef __cplusplus diff --git a/jeeps/gpsmem.c b/jeeps/gpsmem.c index 5bfe84afa..47b3be329 100644 --- a/jeeps/gpsmem.c +++ b/jeeps/gpsmem.c @@ -300,3 +300,42 @@ void GPS_Way_Del(GPS_PWay *thys) return; } +/* @func GPS_Lap_New *********************************************** +** +** Lap constructor +** +** @return [GPS_PLap] virgin track +**********************************************************************/ + +GPS_PLap GPS_Lap_New(void) +{ + GPS_PLap ret; + + if(!(ret=(GPS_PLap)calloc(1,sizeof(GPS_OLap)))) + { + perror("malloc"); + fprintf(stderr,"GPS_Lap_New: Insufficient memory"); + fflush(stderr); + return NULL; + } + + return ret; +} + + + +/* @func GPS_Lap_Del *********************************************** +** +** Lap destructor +** +** @param [w] thys [GPS_PLap *] track to delete +** +** @return [void] +**********************************************************************/ + +void GPS_Lap_Del(GPS_PLap *thys) +{ + free((void *)*thys); + + return; +} diff --git a/jeeps/gpsmem.h b/jeeps/gpsmem.h index f4e5f505d..2f5bbc2ce 100644 --- a/jeeps/gpsmem.h +++ b/jeeps/gpsmem.h @@ -19,6 +19,8 @@ GPS_PTrack GPS_Track_New(void); void GPS_Track_Del(GPS_PTrack *thys); GPS_PWay GPS_Way_New(void); void GPS_Way_Del(GPS_PWay *thys); +GPS_PLap GPS_Lap_New(void); +void GPS_Lap_Del(GPS_PLap *thys); #endif diff --git a/jeeps/gpsprot.c b/jeeps/gpsprot.c index 63976d995..58e8a1182 100644 --- a/jeeps/gpsprot.c +++ b/jeeps/gpsprot.c @@ -37,7 +37,7 @@ static int32 gps_n_tag_unknown = 0; struct COMMANDDATA COMMAND_ID[2]= { { - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x31,0x32,92,117,121,450 + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x31,0x32,92,117,121,450,451,452,453,454,561,562,563,564,564 } , { @@ -48,17 +48,24 @@ struct COMMANDDATA COMMAND_ID[2]= struct LINKDATA LINK_ID[3]= { { - 0x06,0,0,0,0,0,0x15,0,0,0,0,0,0,0,0,0,0xfd,0xfe,0xff + 0xfd,0xfe,0xff,248, + 0x06,0,0,0,0,0,0x15,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } , { - 0x06,0x0a,0x0c,0x0e,0x11,0x13,0x15,0x1b,0x1d,0x1e, - 0x1f,0x22,0x23,0x33,0x62,0x63,0xfd,0xfe,0xff + 0xfd,0xfe,0xff,248, + 0x06,0x0a,0x0c,0x0e,0x11,0x13,0x15,0x1b,0x1d,0x1e,0x1f, + 0x22,0x23,0x33,0x62,0x63, + 134,149,152,990,991,992,993,994,1061,1062,1063,1064,1065,1066,222 } , { + 0xfd,0xfe,0xff,248, 0x06,0x0b,0x0c,0x14,0x18,0,0x15,0x23,0x25,0x27,0x04, - 0,0x2b,0,0,0,0xfd,0xfe,0xff + 0,0x2b,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }; diff --git a/jeeps/gpsprot.h b/jeeps/gpsprot.h index 05ff71857..2e30d20c9 100644 --- a/jeeps/gpsprot.h +++ b/jeeps/gpsprot.h @@ -14,28 +14,44 @@ extern "C" struct LINKDATA { - UC Pid_Ack_Byte; - UC Pid_Command_Data; - UC Pid_Xfer_Cmplt; - UC Pid_Date_Time_Data; - UC Pid_Position_Data; - UC Pid_Prx_Wpt_Data; - UC Pid_Nak_Byte; - UC Pid_Records; - UC Pid_Rte_Hdr; - UC Pid_Rte_Wpt_Data; - UC Pid_Almanac_Data; - UC Pid_Trk_Data; - UC Pid_Wpt_Data; - UC Pid_Pvt_Data; - UC Pid_Rte_Link_Data; - UC Pid_Trk_Hdr; - UC Pid_Protocol_Array; - UC Pid_Product_Rqst; - UC Pid_Product_Data; - UC Pid_Wpt_Cat_Data; -} -; + US Pid_Protocol_Array; + US Pid_Product_Rqst; + US Pid_Product_Data; + US Pid_Ext_Product_Data; + + US Pid_Ack_Byte; + US Pid_Command_Data; + US Pid_Xfer_Cmplt; + US Pid_Date_Time_Data; + US Pid_Position_Data; + US Pid_Prx_Wpt_Data; + US Pid_Nak_Byte; + US Pid_Records; + US Pid_Rte_Hdr; + US Pid_Rte_Wpt_Data; + US Pid_Almanac_Data; + US Pid_Trk_Data; + US Pid_Wpt_Data; + US Pid_Pvt_Data; + US Pid_Rte_Link_Data; + US Pid_Trk_Hdr; + + US Pid_FlightBook_Record; + US Pid_Lap; + US Pid_Wpt_Cat_Data; + US Pid_Run; + US Pid_Workout; + US Pid_Workout_Occurrence; + US Pid_Fitness_User_Profile; + US Pid_Workout_Limits; + US Pid_Course; + US Pid_Course_Lap; + US Pid_Course_Point; + US Pid_Course_Trk_Hdr; + US Pid_Course_Trk_Data; + US Pid_Course_Limits; + US Pid_Trk2_Hdr; /*Undocumented*/ +}; @@ -68,6 +84,15 @@ struct COMMANDDATA US Cmnd_Transfer_Lap; US Cmnd_Transfer_Wpt_Cats; US Cmnd_Transfer_Runs; + US Cmnd_Transfer_Workouts; + US Cmnd_Transfer_Workout_Occurrences; + US Cmnd_Transfer_Fitness_User_Profile; + US Cmnd_Transfer_Workout_Limits; + US Cmnd_Transfer_Courses; + US Cmnd_Transfer_Course_Laps; + US Cmnd_Transfer_Course_Points; + US Cmnd_Transfer_Course_Tracks; + US Cmnd_Transfer_Course_Limits; } ; @@ -121,6 +146,11 @@ int32 gps_almanac_transfer; #define pA600 600 int32 gps_date_time_transfer; +/* + * FlightBook Transfer Protocol + */ +#define pA650 650 +/*Not implemented */ /* * Position @@ -141,10 +171,21 @@ int32 gps_pvt_transfer; #define pA906 906 int32 gps_lap_transfer; +/* + * Various fitness related + */ #define pA1000 1000 int32 gps_run_transfer; - - +#define pA1002 1002 +int32 gps_workout_transfer; +#define pA1004 1004 +int32 gps_user_profile_transfer; +#define pA1005 1005 +int32 gps_workout_limits_transfer; +#define pA1006 1006 +int32 gps_course_transfer; +#define pA1009 1009 +int32 gps_course_limits_transfer; /* * Waypoint D Type @@ -262,9 +303,37 @@ int32 gps_pvt_type; * Lap Data Type */ #define pD906 906 +#define pD1001 1001 +#define pD1011 1011 +#define pD1015 1015 int32 gps_lap_type; +/* + * Various fitness related + */ +#define pD1000 1000 +#define pD1009 1009 +#define pD1010 1010 +int32 gps_run_type; +#define pD1002 1002 +#define pD1008 1008 +int32 gps_workout_type; +#define pD1003 1003 +int32 gps_workout_occurrence_type; +#define pD1004 1004 +int32 gps_user_profile_type; +#define pD1005 1005 +int32 gps_workout_limits_type; +#define pD1006 1006 +int32 gps_course_type; +#define pD1007 1007 +int32 gps_course_lap_type; +#define pD1012 1012 +int32 gps_course_point_type; +#define pD1013 1013 +int32 gps_course_limits_type; + /* * Link protocol type */ -- 2.30.2